package com.google.code.mircle.core;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileLock;

import javax.swing.SwingUtilities;

import org.apache.commons.io.FileUtils;

import com.google.code.mircle.App;
import com.google.code.mircle.core.player.PlayerPlugin;
import com.google.code.mircle.core.shares.SharesPlugin;
import com.google.code.mircle.core.transfers.TransfersPlugin;
import com.google.code.mircle.core.views.ViewsPlugin;
import com.google.code.mircle.plugins.community.CommunityPlugin;
import com.google.code.mircle.plugins.googlereader.GoogleReaderPlugin;
import com.google.code.mircle.plugins.radio.RadioPlugin;
import com.google.code.mircle.plugins.subscriptions.SubscriptionsPlugin;

public class Core {

    public final TransfersPlugin transfers;
    public final PlayerPlugin player;

    public Plugin[] plugins;

    File lock;
    FileOutputStream lockStream;
    FileLock lockStreamLock;

    public App app;

    File shareDir = FileUtils.getFile(System.getProperty("user.home"), ".mircle");
    File pluginsDir = FileUtils.getFile(shareDir, "plugins");

    public Core(App app) {
        this.app = app;

        transfers = new TransfersPlugin(this);
        player = new PlayerPlugin(app);

        plugins = new Plugin[] { new SharesPlugin(), player, transfers, new ViewsPlugin(), new SubscriptionsPlugin(),
                new GoogleReaderPlugin(), new RadioPlugin(), new CommunityPlugin() };
    }

    public void close() {
        for (Plugin p : plugins) {
            p.close();
        }

        save();
    }

    public void save() {
        for (Plugin p : plugins) {
            save(p);
        }

        app.save(shareDir);
    }

    public void save(Plugin p) {
        String klass = p.getClass().getName();
        File f = FileUtils.getFile(pluginsDir, klass);
        p.save(f);
    }

    void lock(File dir) {
        lock = FileUtils.getFile(dir, "lock");
        try {
            lockStream = new FileOutputStream(lock);
            lockStreamLock = lockStream.getChannel().tryLock();
            if (lockStreamLock == null) {
                throw new RuntimeException("already here");
            }
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void load() {
        try {
            FileUtils.forceMkdir(shareDir);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        lock(shareDir);

        for (Plugin p : plugins) {
            String klass = p.getClass().getName();
            File f = FileUtils.getFile(pluginsDir, klass);
            if (f.exists())
                p.load(f);
        }

        app.load(shareDir);
    }

    public static void invoke(Runnable r) {
        SwingUtilities.invokeLater(r);
    }

    public void save(String xml, File f) {
        try {
            FileUtils.forceMkdir(f.getParentFile());
            FileUtils.writeStringToFile(f, xml, "UTF-8");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void invoke(final int delay, final Runnable r) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(delay);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        r.run();
                    }
                });
            }
        }, "Core Invoke Later").start();
    }
}
